var BA_STOP = 0, BA_WRAP = 1, BA_BOUNCE = 2, BA_HIDE = 3, BA_WRAP_X = 4;
var AM_LOOP = 0, AM_STOP = 1, AM_ONCE = 2;
function sprite() {
	this.pos = [0,0];
	this.vel = [0,0];
	this.acc = [0,0];
	this.img_frames = [];   // [ [frame0], [frame1], [frame2] ... ]
	this.img_curfrm = 0;    // current frame idx
	this.img_width = 0;
	this.img_height = 0;
	this.depth = 0.5;
	this.bound_action = BA_STOP;
	this.bound_rect = [0,0,0,0];
	this.visible = true;
	this.anim_cnt = 0;          // animation frame counter
	this.anim_delay = 0;        // update frame delay
	this.anim_type = AM_LOOP;   // animation type
	this.aabb = [0,0,0,0];      // aabb ollision detection box
	this.shrink = 1;            // aabb shrink ratio
}
sprite.prototype.update = function() {
	if (!this.visible)   return;

	this.pos[0] += this.vel[0];
	this.pos[1] += this.vel[1];
	
	this.vel[0] += this.acc[0];
	this.vel[1] += this.acc[1];
	
	var sprx = this.pos[0];       // sprite position x
	var spry = this.pos[1];       // sprite position y
	var sprw = this.img_width;    // sprite width
	var sprh = this.img_height;   // sprite height
	var l = this.bound_rect[0];   // left
	var b = this.bound_rect[1];   // bottom
	var r = this.bound_rect[2];   // right
	var t = this.bound_rect[3];   // top
	if (this.bound_action === BA_STOP) {
		if (sprx < l)                 sprx = l, this.vel = [0,0];
		else if (sprx > (r - sprw))   sprx = r - sprw, this.vel = [0,0];
		if (spry < b)                 spry = b, this.vel = [0,0];
		else if (spry > (t - sprh))   spry = t - sprh, this.vel = [0,0];
	} else if (this.bound_action === BA_WRAP) {
		if ((sprx + sprw) < l)   sprx = r;
		else if (sprx > r)       sprx = l - sprw;
		if ((spry + sprh) < b)   spry = t;
		else if (spry > t)       spry = b - sprh;
	} else if (this.bound_action === BA_BOUNCE) {
		if (sprx < l)                 sprx = l, this.vel[0] = -this.vel[0];
		else if (sprx > (r - sprw))   sprx = r - sprw, this.vel[0] = -this.vel[0];
		if (spry < b)                 spry = b, this.vel[1] = -this.vel[1];
		else if (spry > (t - sprh))   spry = t - sprh, this.vel[1] = -this.vel[1];
	} else if (this.bound_action === BA_HIDE) {
		if ((sprx + sprw) < l || sprx > r || (spry + sprh) < b || spry > t)
			this.visible = false;
	} else if (this.bound_action === BA_WRAP_X) {
		if ((sprx + sprw) < l)   sprx = r;
		else if (sprx > r)       sprx = l - sprw;
		if ((spry + sprh) < b)   this.visible = false;
		else if (spry > t)       this.visible = false;
	}
	this.set_position(sprx, spry);
	
	// update animation
	if (this.anim_delay === 0)   return;
	++this.anim_cnt;
	if (this.anim_cnt === this.anim_delay) {
		this.anim_cnt = 0;    // reset counter
		++this.img_curfrm;   // next frame
		if (this.img_curfrm === this.img_frames.length) {   // it is the last frame
			if (this.anim_type === AM_LOOP)        this.img_curfrm = 0;                            // restart at first frame
			else if (this.anim_type === AM_STOP)   this.img_curfrm = this.img_frames.length - 1;   // stop at last frame
			else if (this.anim_type === AM_ONCE)   this.visible = false;                           // only play once
		}
	}
}
sprite.prototype.draw = function(g) {
	if (!this.visible)   return;
	var srcrc = this.img_frames[this.img_curfrm];
	var dstrc = [this.pos[0], this.pos[1], this.pos[0] + this.img_width, this.pos[1] + this.img_height];
	g.image(256, 256, srcrc, dstrc, this.depth);
}
sprite.prototype.move_left = function(dt)    { this.pos[0] -= dt; }
sprite.prototype.move_right = function(dt)   { this.pos[0] += dt; }
sprite.prototype.move_up = function(dt)      { this.pos[1] += dt; }
sprite.prototype.move_down = function(dt)    { this.pos[1] -= dt; }
sprite.prototype.set_frame_rc = function(rc) {
	this.anim_delay = this.anim_cnt = 0;
	this.img_frames[0] = rc;
	this.img_curfrm = 0;
}
sprite.prototype.set_size = function(w, h) {
	this.img_width = w;
	this.img_height = h;
}
sprite.prototype.set_depth = function(z)           { this.depth = z; }
sprite.prototype.set_position = function(x, y) {
	this.pos[0] = x;
	this.pos[1] = y;
	this.calc_aabb();
}
sprite.prototype.set_velocity = function(x, y)     { this.vel[0] = x, this.vel[1] = y; }
sprite.prototype.set_bound_action = function(ba)   { this.bound_action = ba; }
sprite.prototype.set_bound_rect = function(rc)     { this.bound_rect = rc; }
sprite.prototype.set_visible = function(v)         { this.visible = v; }
sprite.prototype.set_animation_frame_rc = function(rc) {
	this.img_frames = [];
	for (var i in rc)   this.img_frames.push(rc[i]);
	this.img_curfrm = 0;
}
sprite.prototype.set_animation_frame_delay = function(n) {
	this.anim_delay = n;
}
sprite.prototype.set_animation_type = function(at) {
	this.anim_type = at;
}
sprite.prototype.get_position = function()   { return [this.pos[0], this.pos[1]]; }
sprite.prototype.is_visible = function()     { return this.visible; }
sprite.prototype.set_aabb_shrink = function(r)   { this.shrink = r; }
sprite.prototype.calc_aabb = function() {
	var aabbw = this.img_width / this.shrink;
	var aabbh = this.img_height / this.shrink;
	var offx = (this.img_width - aabbw) / 2;
	var offy = (this.img_height - aabbh) / 2;
	this.aabb[0] = this.pos[0] + offx;
	this.aabb[1] = this.pos[1] + offy;
	this.aabb[2] = this.aabb[0] + aabbw;
	this.aabb[3] = this.aabb[1] + aabbh;
}
sprite.prototype.get_aabb = function()       { return this.aabb; }
sprite.prototype.collision = function(spr) {
	var me = {
		left :   this.aabb[0],
		bottom : this.aabb[1],
		right :  this.aabb[2],
		top :    this.aabb[3],
	};
	var it = {
		left :   spr.get_aabb()[0],
		bottom : spr.get_aabb()[1],
		right :  spr.get_aabb()[2],
		top :    spr.get_aabb()[3],
	};
	
	if (me.left > it.right)   return false;
	if (me.right < it.left)   return false;
	if (me.bottom > it.top)   return false;
	if (me.top < it.bottom)   return false;
	return true;
}